/*******************************************************************
This file is part of iDialer.

iDialer is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

iDialer is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with iDialer.  If not, see <http://www.gnu.org/licenses/>.
*******************************************************************/

#include "stdafx.h"
#include <winsock2.h>
#pragma comment(lib, "ws2.lib")
#include <ws2tcpip.h>
#include <strsafe.h>
#include "macros.h"

// the following 3 are for EstablishConnection
#include <initguid.h>
#include <connmgr.h>   //This Include contains all defines for the connection manager
#pragma comment(lib, "cellcore.lib")

// Required for IPIEHTML*
#include <webvw.h>

#include "HTTP.h"

// socket client sample code:
// http://msdn.microsoft.com/en-us/library/ms884931.aspx

#define DEFAULT_FAMILY      AF_UNSPEC
#define DEFAULT_SOCKTYPE    SOCK_STREAM
#define DEFAULT_PORT        "80"
#define BUFFER_SIZE         1024

#define TIMEOUT_SECS        5
#define TIMEOUT_USECS       0

TCHAR tcszErrorMessage[MAX_PATH] = {0};

BOOL EstablishConnection(HANDLE *phConnection);

HRESULT GoogleVoiceMakeCall(const TCHAR * from, const TCHAR * to,
                            IDispatch * pDisp) {

	HRESULT hr = S_OK;
    IPIEHTMLDocument2 * pDocument;
    IPIEHTMLElementCollection * pHTMLElementCollection = NULL;
    IPIEHTMLFormElement * pFormElement = NULL;
	IPIEHTMLElement * pElement = NULL;
    IDispatch * pItem = NULL;
    VARIANT vtIndex;
    VARIANT vtName;
    vtName.vt = VT_I4;
    vtIndex.vt = VT_I4;

	hr = pDisp->QueryInterface<IPIEHTMLDocument2>(&pDocument);
	CHR(hr);

	hr = pDocument->get_forms(&pHTMLElementCollection);
	CHR(hr);
	
    long length = 0;
    hr = pHTMLElementCollection->get_length(&length);

    for (int i = 0; i < (int)length ; i++) {
        vtIndex.lVal = i;
        vtName.lVal = i;

        pHTMLElementCollection->item(vtName, vtIndex, &pItem);

        hr = pItem->QueryInterface(__uuidof(IPIEHTMLFormElement),
            (void **)&pFormElement);

		if(SUCCEEDED(hr))
			break;
	}

	CBR(pFormElement);

	BSTR bstrFormBefore = NULL;
	hr = pFormElement->get_innerHTML(&bstrFormBefore);
	CHR(hr);

	// extract _rnr_se from bstrFormBefore
	// find name="_rnr_se" value="....."
	TCHAR * pRnrse = _tcsstr((TCHAR *)bstrFormBefore,
        TEXT("name=\"_rnr_se\""));
	CBR(pRnrse);
    pRnrse = _tcsstr(pRnrse, TEXT("value=\""))
        + _tcslen(TEXT("value=\""));
    TCHAR * pRnrseEnd = _tcsstr(pRnrse, TEXT("\""));
    CBR(pRnrseEnd);
	TCHAR rnrse[64];
    StringCchCopyN(rnrse, 64, pRnrse, pRnrseEnd - pRnrse);

	// slightly hacky, but not too bad: rebuild form to do my bidding
	TCHAR szForm[512] = {0};
	StringCchPrintf(szForm, 512,
		TEXT("<input type=\"hidden\" name=\"_rnr_se\" value=\"%s\"/>")
	    TEXT("<input type=\"hidden\" name=\"number\" value=\"%s\"/>")
	    TEXT("<input type=\"hidden\" name=\"phone\" value=\"%s\"/>"),
		rnrse, to, from);

	BSTR bstrForm = NULL;
	bstrForm = SysAllocString(szForm);

	hr = pFormElement->put_innerHTML(bstrForm);

#if DEBUG
	BSTR bstrFormAfter = NULL;
	hr = pFormElement->get_innerHTML(&bstrFormAfter);
	CHR(hr);
#endif

	//To debug, modify the form action and run this on aztec:
	//sudo tcpdump -A -s 10240 port 80 and host aztec.supbro.com
	//BSTR bstrAction = BSTR(TEXT("http://aztec.supbro.com/blah.php"));

	BSTR bstrAction = BSTR(TEXT("/voice/m/sendcall"));
	hr = pFormElement->put_action(bstrAction);
	CHR(hr);

	hr = pFormElement->submit();
	CHR(hr);

Error:
	RELEASE_OBJ(pDocument);
	RELEASE_OBJ(pFormElement);
	RELEASE_OBJ(pHTMLElementCollection);
	RELEASE_OBJ(pElement);
	RELEASE_OBJ(pItem);

	return hr;
}

//
// EXAMPLE JaJah Minimal Session
// host: mobile.jajah.com
//

/*
request:
POST http://mobile.jajah.com/mobilemini/
User-Agent: libwww-perl/5.808
Content-Length: 83
Content-Type: application/x-www-form-urlencoded

ctl00%24MainContent%24Email=my%40email.com&ctl00%24MainContent%24Password=mysecret

~~~~~

response:
HTTP/1.1 302 Found
Cache-Control: no-cache
Connection: close
Date: Fri, 31 Oct 2008 22:34:06 GMT
Pragma: no-cache
Location: http://mobile.jajah.com/mobilemini/member.aspx?
Server: Microsoft-IIS/6.0
Content-Length: 167
Content-Type: text/html; charset=utf-8
Expires: -1
Client-Date: Fri, 31 Oct 2008 22:30:48 GMT
Client-Peer: 91.194.4.112:80
Client-Response-Num: 1
P3P: CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT"
Set-Cookie: jajahcook=a52...4; path=/
Set-Cookie: ASP.NET_SessionId=yhc...b; path=/; HttpOnly
Set-Cookie: SERVERIP=1032; path=/; HttpOnly
Set-Cookie: jj=login=my@email.com; expires=Sat, 31-Oct-2009 22:34:06 GMT; path=/; HttpOnly
Set-Cookie: .ASPXAUTH=B0E1A1...5; domain=jajah.com; path=/; HttpOnly
X-AspNet-Version: 2.0.50727
X-Powered-By: ASP.NET

?<html><head><title>Object moved</title></head><body>
<h2>Object moved to <a href="http://mobile.jajah.com/mobilemini/member.aspx?">here</a>.</h2>
</body></html>

~~~~~~~~~~~~~~~~

request:
GET http://mobile.jajah.com/mobilemini/status.aspx?s=+1858.......&d=1858.......&name=&type=1
User-Agent: libwww-perl/5.808
Cookie: .ASPXAUTH=B0E1A....A5;

~~~~

response:
HTTP/1.1 200 OK
Cache-Control: no-cache
Connection: close
Date: Fri, 31 Oct 2008 22:35:25 GMT
Pragma: no-cache
Server: Microsoft-IIS/6.0
Content-Length: 572
Content-Type: text/html; charset=utf-8
Expires: -1
Client-Date: Fri, 31 Oct 2008 22:32:07 GMT
Client-Peer: 91.194.4.112:80
Client-Response-Num: 1
P3P: CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT"
Set-Cookie: jajahcook=a52...e; path=/
Set-Cookie: ASP.NET_SessionId=vkv...5; path=/; HttpOnly
Set-Cookie: SERVERIP=1027; path=/; HttpOnly
Set-Cookie: jjnumber=1858.......; expires=Sat, 31-Oct-2009 22:35:25 GMT; path=/; HttpOnly
Set-Cookie: jj=mobileminicall=10/31/2008 11:35:25 PM; path=/
X-Powered-By: ASP.NET

?
<html>
<head>
<title>JAJAH Mobile Web</title>


</head>
<body >
<form name="theForm" id="theForm" method="post" action="member.aspx">
<font color="purple" size="2" face="Arial"><b id="ctl00_HeadLine">mobile.jajah.com - USD 0.22<br /></b></font>


  <b>Your phone will ring -<br /> please pick up.</b><br /><br />
   <b>+1858.......</b><br />
   (This call costs USD 0.029/min.<br>YOU SAVED 73%)<br />
    <input type="submit" value="OK" /><br />
    <a href="addcontact.aspx?num=1-858.......">add this number</a>
  
</font>
</form>
</body>
</html>

*/

HRESULT HttpJaJahDial(const TCHAR * tszFromNumber, 
                      const TCHAR * tszToNumber, 
                      const TCHAR * tszUsername, 
                      const TCHAR * tszPassword) {

    HRESULT hr = S_OK;
    TCHAR tszRequestString[1024];
    TCHAR tszResponseString[2048];
    TCHAR buffer[128];

    TCHAR tszAuth[300];

    TCHAR * pResp;
    TCHAR * pCookie;
    TCHAR * pEqual;
    TCHAR * pSemi;
    TCHAR * pError;
    int cbContentLength;

    // login to JaJah account
    StringCchPrintf(buffer, 128, 
        TEXT("ctl00%%24MainContent%%24Email=%s&ctl00%%24MainContent%%24Password=%s"),
        tszUsername, tszPassword);

    cbContentLength = wcslen(buffer);
    StringCchPrintf(tszRequestString, 1024,
        TEXT("POST /mobilemini/ HTTP/1.0\r\nContent-Length: %d\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\n%s\r\n"),
        cbContentLength, buffer);
    hr = SendHttp(TEXT("mobile.jajah.com"), tszRequestString, tszResponseString, 2048);
    if (FAILED(hr)) {
        StringCchCopy(tcszErrorMessage, MAX_PATH,
            TEXT("ERROR: Unexpected results returned from JaJah login"));
        goto Error;
    }

    // parse cookies from response
    // looking for:
    // Set-Cookie: .ASPXAUTH=B0E1A1...5; domain=jajah.com; path=/; HttpOnly

    pResp = tszResponseString;
    pCookie = wcsstr(pResp, TEXT("Set-Cookie: "));
    while (pCookie != NULL) {
        pCookie += 12; // length of "Set-Cookie: "
        pEqual = wcsstr(pCookie, TEXT("="));
        pSemi = wcsstr(pCookie, TEXT(";"));
        if (pSemi - pEqual > 1) {
            if (wcsstr(pCookie, TEXT(".ASPXAUTH")) == pCookie) {
                StringCchCopyN(tszAuth, 300, pEqual + 1, pSemi - pEqual - 1);
            }
        }
        pCookie = wcsstr(pCookie, TEXT("Set-Cookie: "));
    }

    // verify we have all the proper cookie variables
    if (_tcslen(tszAuth) == 0) {
        StringCchCopy(tcszErrorMessage, MAX_PATH,
            TEXT("ERROR: Unable to login to JaJah"));
        hr = E_FAIL;
        goto Error;
    }

    // Look for an error message from JaJah
    pError = wcsstr(pResp, TEXT("<div style=\"background-color:Yellow;\"><font color=\"black\">"));
    if (pError != NULL) {
        pError += 58; // length of that "<div..<font..>"
        pSemi = wcsstr(pError, TEXT("<"));
        StringCchCopyN(tcszErrorMessage, MAX_PATH, pError, pSemi - pError);
        hr = E_FAIL;
        goto Error;
    }

    // send request to dial
    StringCchPrintf(tszRequestString, 1024, 
        TEXT("GET /mobilemini/status.aspx?s=%s&d=%s&name=&type=1 HTTP/1.0\r\nCookie: .ASPXAUTH=%s; \r\n\r\n"), 
        tszFromNumber, tszToNumber, tszAuth);

    hr = SendHttp(TEXT("mobile.jajah.com"), tszRequestString, tszResponseString, 2048);

    // Look for an error message from JaJah
    pError = wcsstr(pResp, TEXT("<div style=\"background-color:Yellow;\"><font color=\"black\">"));
    if (pError != NULL) {
        pError += 58; // length of that "<div..<font..>"
        pSemi = wcsstr(pError, TEXT("<"));
        StringCchCopyN(tcszErrorMessage, MAX_PATH, pError, pSemi - pError);
        hr = E_FAIL;
        goto Error;
    }

    // "Your phone will ring" means successful
    if (NULL == wcsstr(tszResponseString, TEXT("Your phone will ring"))) {
        StringCchCopy(tcszErrorMessage, MAX_PATH,
            TEXT("ERROR: Uknown JaJah error"));
        hr = E_FAIL;
        goto Error;
    }

    hr = S_OK;

Error:
    return hr;
}

HRESULT SendHttp(const TCHAR * tszRemoteHost, const TCHAR * tszRequest, 
                 TCHAR * tszResponse, size_t cchResponse) {

    HANDLE hConnection = 0;
    HRESULT hr = S_OK;
    SOCKET sock = INVALID_SOCKET;
    int nFamily = DEFAULT_FAMILY;
    int nSockType = DEFAULT_SOCKTYPE;
    
    char szRemoteHost[64];
    char szRemoteAddrString[128];
    char szRequest[BUFFER_SIZE];
    char *szPort = DEFAULT_PORT;

    SOCKADDR_STORAGE ssRemoteAddr;
    int cbRequest, cbXfer, cbTotalRecvd, cbRemoteAddrSize;
    WSADATA wsaData;
    ADDRINFO Hints, *AddrInfo = NULL, *AI;
    fd_set fdReadSet;
    TIMEVAL timeout = {TIMEOUT_SECS, TIMEOUT_USECS};

    char pRecvBuf[BUFFER_SIZE];

    //
    // Establish Internet Connection
    //

    BOOL success = EstablishConnection(&hConnection);
    if (!success) {
        StringCchCopy(tcszErrorMessage, MAX_PATH,
            TEXT("ERROR: Could not establish Internet Connection!"));
        CHR(E_FAIL);
    }

    if (WSAStartup(MAKEWORD(2,2), &wsaData)) {
        // WSAStartup failed
        CHR(E_FAIL);
    }

    wcstombs(szRemoteHost, tszRemoteHost, 64);

    //
    // Resolve the server name/address
    //

    memset(&Hints, 0, sizeof(Hints));
    Hints.ai_family = nFamily;
    Hints.ai_socktype = nSockType;

    if(getaddrinfo(szRemoteHost, szPort, &Hints, &AddrInfo)) {
        //MessageBox(NULL, (LPCWSTR)szRemoteHost, TEXT("Remote Host"), 0);
        //MessageBox(NULL, (LPCWSTR)szPort, TEXT("Port"), 0);
        StringCchCopy(tcszErrorMessage, MAX_PATH,
            TEXT("ERROR: Couldn't resolve the server name/address!"));
        CHR(E_FAIL);
    }

    //
    // Attempt to connect to each address until we find one that succeeds
    //

    for (AI = AddrInfo; AI != NULL; AI = AI->ai_next) {
        // only want PF_INET or PF_INET6
        if ((AI->ai_family == PF_INET) || (AI->ai_family == PF_INET6)) {

            sock = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol);
            if (sock != INVALID_SOCKET) {

                if (AI->ai_socktype == SOCK_STREAM) {

                    if (connect(sock, AI->ai_addr, AI->ai_addrlen) == SOCKET_ERROR) {
                        // Connect failed, let's close this socket and try again on the next address in the list
                        closesocket(sock);
                        continue;
                    }
                }

                // connect() succeeded or we're a UDP socket
                break;
            }
        }
    }
    
    if (AI == NULL) {
        StringCchCopy(tcszErrorMessage, MAX_PATH,
            TEXT("ERROR: Unable to connect socket!"));
        CHR(E_FAIL);
    }

    //
    // Send data to the server
    //

    wcstombs(szRequest, tszRequest, BUFFER_SIZE);
    cbRequest = strlen(szRequest);
    cbXfer = 0;
    cbXfer = sendto(sock, szRequest, cbRequest, 0, AI->ai_addr, AI->ai_addrlen);

    if(cbXfer != cbRequest) {
        StringCchPrintf(tcszErrorMessage, MAX_PATH, 
            TEXT("ERROR: request failed! error = %d"), WSAGetLastError());
        CHR(E_FAIL);
    }

    if (getnameinfo(AI->ai_addr, AI->ai_addrlen,
        szRemoteAddrString, sizeof(szRemoteAddrString), NULL, 0, NI_NUMERICHOST) != 0) {
        strcpy(szRemoteAddrString, "");

        StringCchPrintf(tcszErrorMessage, MAX_PATH, 
            TEXT("Sent %d bytes successfully"), cbXfer);
    }

    //
    // Receive the response from the server
    //

    FD_ZERO(&fdReadSet);
    FD_SET(sock, &fdReadSet);

    if (select(0, &fdReadSet, NULL, NULL, &timeout) != 1) {

        StringCchPrintf(tcszErrorMessage, MAX_PATH, 
            TEXT("ERROR: Server hasn't responded in %d milliseconds"), 
            ((timeout.tv_sec * 1000) + (timeout.tv_sec / 1000)));
        CHR(E_FAIL);
    }

    cbTotalRecvd = 0;
    do {
        cbRemoteAddrSize = sizeof(ssRemoteAddr);
        cbXfer = recvfrom(sock, pRecvBuf + cbTotalRecvd, 
            sizeof(pRecvBuf) - cbTotalRecvd, 0, 
            (SOCKADDR *)&ssRemoteAddr, &cbRemoteAddrSize);
        cbTotalRecvd += cbXfer;
    } while(cbXfer > 0 && cbTotalRecvd < sizeof(pRecvBuf));

    if(cbXfer == SOCKET_ERROR) {
        StringCchPrintf(tcszErrorMessage, MAX_PATH, 
            TEXT("ERROR: Couldn't receive the data! Error = %d"), 
            WSAGetLastError());
        CHR(E_FAIL);
    }

    if(nSockType == SOCK_STREAM) {
        cbRemoteAddrSize = sizeof(ssRemoteAddr);
        memset(&ssRemoteAddr, 0, cbRemoteAddrSize);
        getpeername(sock, (SOCKADDR *)&ssRemoteAddr, &cbRemoteAddrSize);
    }

    if (0 != getnameinfo((SOCKADDR *)&ssRemoteAddr, cbRemoteAddrSize,
        szRemoteAddrString, sizeof(szRemoteAddrString), 
        NULL, 0, NI_NUMERICHOST)) {

        strcpy(szRemoteAddrString, "");
    }

    mbstowcs(tszResponse, pRecvBuf, cchResponse);

    hr = S_OK;
Error:
    if (sock != INVALID_SOCKET) {
        shutdown(sock, SD_BOTH);
        closesocket(sock);
    }

    if (AddrInfo)
        freeaddrinfo(AddrInfo);

    if (hConnection)
        ::ConnMgrReleaseConnection(hConnection, true);

    WSACleanup();

    return hr;
}


int sockettest () {
    SOCKET sock = INVALID_SOCKET;
    int nFamily = DEFAULT_FAMILY;
    int nSockType = DEFAULT_SOCKTYPE;
    char szRemoteName[64];
    char *szPort = DEFAULT_PORT;
    SOCKADDR_STORAGE ssRemoteAddr;
    int cbXfer, cbTotalRecvd, cbRemoteAddrSize;
    WSADATA wsaData;
    ADDRINFO Hints, *AddrInfo = NULL, *AI;
    char szRemoteAddrString[128];
    fd_set fdReadSet;
    TIMEVAL timeout = {TIMEOUT_SECS, TIMEOUT_USECS};
    char pRecvBuf[BUFFER_SIZE];
    TCHAR MessageBuffer[BUFFER_SIZE];
    TCHAR MessageBuffer2[BUFFER_SIZE];
    char pBuf[] = "GET /iDialer/test.php HTTP/1.0\n\n";

    if(WSAStartup(MAKEWORD(2,2), &wsaData)) {
        // WSAStartup failed
        return 1;
    }

    wcstombs(szRemoteName, TEXT("supware.net"), 64);

    StringCchCopy(MessageBuffer, BUFFER_SIZE, 
        TEXT("Communicating with server - supware.net\r\n"));
    MessageBox(NULL, MessageBuffer, TEXT("HTTP"), 0);

    //
    // Resolve the server name/address
    //

    memset(&Hints, 0, sizeof(Hints));
    Hints.ai_family = nFamily;
    Hints.ai_socktype = nSockType;

    if(getaddrinfo(szRemoteName, szPort, &Hints, &AddrInfo)) {
        StringCchPrintf(MessageBuffer, BUFFER_SIZE, 
            TEXT("ERROR: Couldn't get resolve the server name/address!"));
        MessageBox(NULL, MessageBuffer, TEXT("HTTP"), 0);

    goto Cleanup;
    }

    //
    // Attempt to connect to each address until we find one that succeeds
    //

    for(AI = AddrInfo; AI != NULL; AI = AI->ai_next) {
        // only want PF_INET or PF_INET6
        if((AI->ai_family == PF_INET) || (AI->ai_family == PF_INET6)) {

            sock = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol);
            if (sock != INVALID_SOCKET) {

                if (AI->ai_socktype == SOCK_STREAM) {

                    if (connect(sock, AI->ai_addr, AI->ai_addrlen) == SOCKET_ERROR) {
                        // Connect failed, let's close this socket and try again on the next address in the list
                        closesocket(sock);
                        continue;
                    }
                }

                // connect() succeeded or we're a UDP socket
                break;
            }
        }
    }
    
    if (AI == NULL) {
        StringCchPrintf(MessageBuffer, BUFFER_SIZE, 
            TEXT("ERROR: Unable to connect to any of the server's addresses!"));
        MessageBox(NULL, MessageBuffer, TEXT("HTTP"), 0);
        goto Cleanup;
    }

    //
    // Send data to the server
    //

    cbXfer = 0;
    cbXfer = sendto(sock, pBuf, sizeof(pBuf), 0, AI->ai_addr, AI->ai_addrlen);

    if(cbXfer != sizeof(pBuf)) {
        StringCchPrintf(MessageBuffer, BUFFER_SIZE, 
            TEXT("ERROR: Couldn't send the data! error = %d"), WSAGetLastError());
        MessageBox(NULL, MessageBuffer, TEXT("HTTP"), 0);

        goto Cleanup;
    }

    if (getnameinfo(AI->ai_addr, AI->ai_addrlen,
        szRemoteAddrString, sizeof(szRemoteAddrString), NULL, 0, NI_NUMERICHOST) != 0)
        strcpy(szRemoteAddrString, "");
    
    mbstowcs(MessageBuffer2, szRemoteAddrString, BUFFER_SIZE);
    StringCchPrintf(MessageBuffer, BUFFER_SIZE, 
        TEXT("SUCCESS - Sent %d bytes to address %s"), cbXfer, MessageBuffer2);
    MessageBox(NULL, MessageBuffer, TEXT("HTTP"), 0);

    //
    // Receive the echo'd data back from the server
    //

    FD_ZERO(&fdReadSet);
    FD_SET(sock, &fdReadSet);

    if(select(0, &fdReadSet, NULL, NULL, &timeout) != 1) {
        StringCchPrintf(MessageBuffer, BUFFER_SIZE, 
            TEXT("ERROR: Server hasn't responded in %d milliseconds"), 
            ((timeout.tv_sec * 1000) + (timeout.tv_sec / 1000)));
        MessageBox(NULL, MessageBuffer, TEXT("HTTP"), 0);

        goto Cleanup;
    }

    cbTotalRecvd = 0;
    do {
        cbRemoteAddrSize = sizeof(ssRemoteAddr);
        cbXfer = recvfrom(sock, pRecvBuf + cbTotalRecvd, 
            sizeof(pRecvBuf) - cbTotalRecvd, 0, 
            (SOCKADDR *)&ssRemoteAddr, &cbRemoteAddrSize);
        cbTotalRecvd += cbXfer;
    } while(cbXfer > 0 && cbTotalRecvd < sizeof(pRecvBuf));

    if(cbXfer == SOCKET_ERROR) {
        StringCchPrintf(MessageBuffer, BUFFER_SIZE, 
            TEXT("ERROR: Couldn't receive the data! Error = %d"), 
            WSAGetLastError());
        MessageBox(NULL, MessageBuffer, TEXT("HTTP"), 0);

        goto Cleanup;
    }

    if(nSockType == SOCK_STREAM) {
        memset(&ssRemoteAddr, 0, sizeof(ssRemoteAddr));
        cbRemoteAddrSize = sizeof(ssRemoteAddr);
        getpeername(sock, (SOCKADDR *)&ssRemoteAddr, &cbRemoteAddrSize);
    }

    if (getnameinfo((SOCKADDR *)&ssRemoteAddr, cbRemoteAddrSize,
        szRemoteAddrString, sizeof(szRemoteAddrString), NULL, 0, NI_NUMERICHOST) != 0)
        strcpy(szRemoteAddrString, "");

    mbstowcs(MessageBuffer2, pRecvBuf, BUFFER_SIZE);
    StringCchPrintf(MessageBuffer, BUFFER_SIZE, 
        TEXT("SUCCESS - Received %d bytes back from address %s: %s"), 
        cbTotalRecvd, szRemoteAddrString, MessageBuffer2);

    MessageBox(NULL, MessageBuffer, TEXT("HTTP"), 0);

Cleanup:

    if(sock != INVALID_SOCKET)
    {
        shutdown(sock, SD_BOTH);
        closesocket(sock);
    }

    if(AddrInfo)
        freeaddrinfo(AddrInfo);

    WSACleanup();

    return 0;
} 

void GetHttpErrorMessage(TCHAR * to, int cchTo) {
    StringCchCopy(to, cchTo, tcszErrorMessage);
}

BOOL EstablishConnection(HANDLE *phConnection) {
    CONNMGR_CONNECTIONINFO conn = {0};
    DWORD dwStatus;

    conn.cbSize = sizeof(CONNMGR_CONNECTIONINFO);
    conn.dwPriority = CONNMGR_PRIORITY_USERINTERACTIVE;
    conn.bExclusive = false;
    conn.dwParams = CONNMGR_PARAM_GUIDDESTNET;
    conn.guidDestNet = IID_DestNetInternet;
    conn.dwFlags = 0;
    conn.bExclusive = FALSE;
    conn.bDisabled = FALSE;
    //TODO: these are for asynchronous
    //conn.hWnd
    //conn.uMsg
    //conn.lParam

    ConnMgrConnectionStatus(phConnection, &dwStatus);

    if (dwStatus != CONNMGR_STATUS_CONNECTED) {
        // Not connected, try to establish the connection
        ::ConnMgrEstablishConnectionSync(&conn, phConnection, 60000, &dwStatus);
    }

    if (dwStatus != CONNMGR_STATUS_CONNECTED) {
        TCHAR message[32];
        StringCchPrintf(message, 32, TEXT("unable to connect: 0x%x"), dwStatus);
        MessageBox(NULL, message, NULL, 0);
    }

    return dwStatus == CONNMGR_STATUS_CONNECTED;
}